package org.ko.commons.util;

/**
 * Copyright &copy; 2012-2013 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;

import com.google.common.collect.Maps;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 代码生成器
 * @author ThinkGem
 * @version 2013-06-21
 * 
 * modify on 2014-9-22 by zengxm
 * 增加了Model层的创建
 */
public final class Generate {
	
	private static Logger logger = LoggerFactory.getLogger(Generate.class);

	/**
	 * 
	 * GenerateBean
	 * @author zengxm
	 * @date 2014-9-4
	 * @version 1.0.0
	 */
	public static class GenerateBean{
		private String packageName;
		private String moduleName;
		private String subModuleName;
		private String className;
		private String classAuthor;
		private String comment;
		private String classChineseName;	//模块中文名
		
		private boolean createEntity = true;	//生成实体类
		private boolean createService = true;	//生成service
		private boolean createDao = true;		//生成dao
		private boolean createController = true;	//生成controller
		private boolean createModel = true;		//生成model
		
		private boolean clean = false;		//是否清空代码生成的文件，慎用！
		
		public boolean isClean() {
			return clean;
		}
		public void setClean(boolean clean) {
			this.clean = clean;
		}
		public boolean isCreateModel() {
			return createModel;
		}
		public void setCreateModel(boolean createModel) {
			this.createModel = createModel;
		}
		public boolean isCreateEntity() {
			return createEntity;
		}
		public void setCreateEntity(boolean createEntity) {
			this.createEntity = createEntity;
		}
		public boolean isCreateService() {
			return createService;
		}
		public void setCreateService(boolean createService) {
			this.createService = createService;
		}
		public boolean isCreateDao() {
			return createDao;
		}
		public void setCreateDao(boolean createDao) {
			this.createDao = createDao;
		}
		public boolean isCreateController() {
			return createController;
		}
		public void setCreateController(boolean createController) {
			this.createController = createController;
		}
		public String getClassChineseName() {
			return classChineseName;
		}
		public void setClassChineseName(String classChineseName) {
			this.classChineseName = classChineseName;
		}
		public String getSubModuleName() {
			return subModuleName;
		}
		public void setSubModuleName(String subModuleName) {
			this.subModuleName = subModuleName;
		}
		public String getPackageName() {
			return packageName;
		}
		public void setPackageName(String packageName) {
			this.packageName = packageName;
		}
		public String getModuleName() {
			return moduleName;
		}
		public void setModuleName(String moduleName) {
			this.moduleName = moduleName;
		}
		public String getClassName() {
			return className;
		}
		public void setClassName(String className) {
			this.className = className;
		}
		public String getClassAuthor() {
			return classAuthor;
		}
		public void setClassAuthor(String classAuthor) {
			this.classAuthor = classAuthor;
		}
		public String getComment() {
			return comment;
		}
		public void setComment(String comment) {
			this.comment = comment;
		}
	}
	
	
	public static void generate(GenerateBean gb) throws Exception {

		// ========== ↓↓↓↓↓↓ 执行前请修改参数，谨慎执行。↓↓↓↓↓↓ ====================

		// 主要提供基本功能模块代码生成。
		// 目录生成结构：{packageName}/{moduleName}/{dao,entity,service,web}/{subModuleName}/{className}
		
		// packageName 包名，这里如果更改包名，请在applicationContext.xml和srping-mvc.xml中配置base-package、packagesToScan属性，来指定多个（共4处需要修改）。
		String packageName = gb.getPackageName();
		
		String moduleName = gb.getModuleName();			// 模块名，例：sys
		String subModuleName = gb.getSubModuleName();	// 子模块名（可选） 
		String className = gb.getClassName();			// 类名，例：user
		String classAuthor = gb.getClassAuthor();		// 类作者，例：ThinkGem
		String functionName = gb.getComment();			// 功能名，例：用户

		// 是否启用生成工具
		Boolean isEnable = true;			
		
		// ========== ↑↑↑↑↑↑ 执行前请修改参数，谨慎执行。↑↑↑↑↑↑ ====================
		
		if (!isEnable){
			logger.error("请启用代码生成工具，设置参数：isEnable = true");
			return;
		}
		
		if (StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleName) 
				|| StringUtils.isBlank(className) || StringUtils.isBlank(functionName)){
			logger.error("参数设置错误：包名、模块名、类名、功能名不能为空。");
			return;
		}
		
		// 获取文件分隔符
		String separator = File.separator;
		
		// 获取工程路径
		File projectPath = new DefaultResourceLoader().getResource("").getFile();
		System.out.println(projectPath);
		System.out.println(new File(projectPath.getPath()+separator+gb.getModuleName()).getParentFile());
		while(!new File(projectPath.getPath()+separator+"WebRoot").exists()){
			projectPath = projectPath.getParentFile();
		}
		
		logger.info("Project Path: {}", projectPath);
		
		// 模板文件路径
		String tplPath = StringUtils.replace(projectPath+"/resources/tpl", "/", separator);
		logger.info("Template Path: {}", tplPath);
		
		// Java文件路径
		String javaPath = projectPath+StringUtils.replaceEach("/src/"+StringUtils.lowerCase(packageName), 
				new String[]{"/", "."}, new String[]{separator, separator});
		logger.info("Java Path: {}", javaPath);
		
		// 视图文件路径
		String viewPath = StringUtils.replace(projectPath+"/webapp/WEB-INF/modules/", "/", separator);
		logger.info("View Path: {}", viewPath);
		
		// 代码模板配置
		Configuration cfg = new Configuration();
		cfg.setDirectoryForTemplateLoading(new File(tplPath));

		// 定义模板变量
		Map<String, String> model = Maps.newHashMap();
		model.put("curDate", DateUtil.getDate());
		model.put("classNameChinese", gb.getClassChineseName());
		model.put("packageName", StringUtils.lowerCase(packageName));
		model.put("moduleName", StringUtils.lowerCase(moduleName));
		model.put("subModuleName", StringUtils.isNotBlank(subModuleName)?"."+StringUtils.lowerCase(subModuleName):"");
		model.put("className", StringUtils.uncapitalize(className));
		model.put("ClassName", StringUtils.capitalize(className));
		model.put("classAuthor", StringUtils.isNotBlank(classAuthor)?classAuthor:"Generate Tools");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		model.put("classVersion", sdf.format(new Date()));
		model.put("functionName", functionName);
		model.put("tableName", model.get("moduleName")+(StringUtils.isNotBlank(subModuleName)
				?"_"+StringUtils.lowerCase(subModuleName):"")+"_"+model.get("className"));
		model.put("urlPrefix", model.get("moduleName")+(StringUtils.isNotBlank(subModuleName)
				?"/"+StringUtils.lowerCase(subModuleName):"")+"/"+model.get("className"));
		model.put("viewPrefix", StringUtils.substringAfterLast(model.get("packageName"),".")
				+"/"+model.get("urlPrefix"));
		model.put("permissionPrefix", model.get("moduleName")+(StringUtils.isNotBlank(subModuleName)
				?":"+StringUtils.lowerCase(subModuleName):"")+":"+model.get("className"));

		
		Template template = null;
		String content = null, filePath= null;
		// 生成 Entity
		if(gb.isCreateEntity()){
			template = cfg.getTemplate("domain.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"domain"
					+separator+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+".java";
				
			writeFile(content, filePath, gb.isClean());
			logger.info("Entity: {}", filePath);
		}
		
		/*
		 * 直接生成dao
		 */
		if(gb.isCreateDao()){
			template = cfg.getTemplate("dao.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"dao"+separator
					+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"Dao.java";
			writeFile(content, filePath, gb.isClean());
			logger.info("Dao: {}", filePath);
			
		}
		
		/*
		 * 生成Model
		 */
		if(gb.isCreateModel()){
			template = cfg.getTemplate("model.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"controller"+separator+"model"+separator
					+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"Model.java";
			writeFile(content, filePath, gb.isClean());
			logger.info("Model: {}", filePath);
		}
		
		/**
		 * 如果需要用到 dao 接口，就使用下面的代码
		 */
//		// 生成 Dao
//		template = cfg.getTemplate("dao-interface.ftl");
//		content = FreeMarkers.renderTemplate(template, model);
//		filePath = javaPath+separator+model.get("moduleName")+separator+"dao"+separator
//				+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"Dao.java";
//		writeFile(content, filePath);
//		logger.info("Dao: {}", filePath);
//		
//		// 生成 DaoImpl
//		template = cfg.getTemplate("daoimpl.ftl");
//		content = FreeMarkers.renderTemplate(template, model);
//		filePath = javaPath+separator+model.get("moduleName")+separator+"dao"+separator+"impl"+separator+model.get("ClassName")+"DaoImpl.java";
//		writeFile(content, filePath);
//		logger.info("DaoImpl: {}", filePath);
		
		// 生成 Service
		if(gb.isCreateService()){
			template = cfg.getTemplate("service.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"service"+separator
					+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"Service.java";
			writeFile(content, filePath, gb.isClean());
			logger.info("Svc: {}", filePath);
			// 生成 Service
			template = cfg.getTemplate("serviceimpl.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"service"+separator+"impl"+separator
			+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"ServiceImpl.java";
			writeFile(content, filePath, gb.isClean());
			logger.info("SvcImpl: {}", filePath);
		}
		
		
		
		
		
		// 生成 Controller
		if(gb.isCreateController()){
			template = cfg.getTemplate("controller.ftl");
			content = FreeMarkers.renderTemplate(template, model);
			filePath = javaPath+separator+model.get("moduleName")+separator+"controller"+separator
					+StringUtils.lowerCase(subModuleName)+separator+model.get("ClassName")+"Controller.java";
			writeFile(content, filePath, gb.isClean());
			logger.info("Controller: {}", filePath);
		}
		
		
		/*
		 * 暂时不生成view相关的文件
		 */
		// 生成 ViewForm
//		template = cfg.getTemplate("form_add.ftl");
//		content = FreeMarkers.renderTemplate(template, model);
//		filePath = viewPath
//				+separator+model.get("moduleName") + separator+model.get("className").toLowerCase()+ separator+"add.html";
//		writeFile(content, filePath);
//		logger.info("ViewForm: {}", filePath);
//		// 生成 ViewForm
//		template = cfg.getTemplate("form_edit.ftl");
//		content = FreeMarkers.renderTemplate(template, model);
//		filePath = viewPath
//		+separator+model.get("moduleName") + separator+model.get("className").toLowerCase()+ separator+"edit.html";
//		writeFile(content, filePath);
//		logger.info("ViewForm: {}", filePath);
//		// 生成 ViewForm
//		template = cfg.getTemplate("form_list.ftl");
//		content = FreeMarkers.renderTemplate(template, model);
//		filePath = viewPath
//		+separator+model.get("moduleName") + separator+model.get("className").toLowerCase()+ separator+"list.html";
//		writeFile(content, filePath);
//		logger.info("ViewForm: {}", filePath);
		
		/*
		// 生成 ViewList
		template = cfg.getTemplate("viewList.ftl");
		content = FreeMarkers.renderTemplate(template, model);
		filePath = viewPath+separator+StringUtils.substringAfterLast(model.get("packageName"),".")
				+separator+model.get("moduleName")+separator+StringUtils.lowerCase(subModuleName)
				+separator+model.get("className")+"List.jsp";
		writeFile(content, filePath);
		logger.info("ViewList: {}", filePath);
		
		logger.info("Generate Success.");
		*/
	}
	public static boolean createFile(String descFileName, boolean isClean) {
		File file = new File(descFileName);
		if (file.exists()) {
			if(isClean){
				file.delete();
			}else{
				logger.debug("文件 " + descFileName + " 已存在!");
				return false;
			}
		}
		if (descFileName.endsWith(File.separator)) {
			logger.debug(descFileName + " 为目录，不能创建目录!");
			return false;
		}
		if (!file.getParentFile().exists()) {
			// 如果文件所在的目录不存在，则创建目录
			if (!file.getParentFile().mkdirs()) {
				logger.debug("创建文件所在的目录失败!");
				return false;
			}
		}

		// 创建文件
		try {
			if (file.createNewFile()) {
				logger.debug(descFileName + " 文件创建成功!");
				return true;
			} else {
				logger.debug(descFileName + " 文件创建失败!");
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.debug(descFileName + " 文件创建失败!");
			return false;
		}

	}
	/**
	 * 将内容写入文件
	 * @param content
	 * @param filePath
	 */
	public static void writeFile(String content, String filePath, boolean isClean) {
		try {
			if (createFile(filePath, isClean)){
				FileWriter fileWriter = new FileWriter(filePath, true);
				BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write(content);
				bufferedWriter.close();
				fileWriter.close();
			}else{
				logger.info("生成失败，文件已存在！");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
